package com.sos.core.cards
{
	
	import com.sos.Application;
	import com.sos.core.DataObject;
	import com.sos.core.DispatcherDataObject;
	import com.sos.core.School;
	import com.sos.logging.Dumper;
	import com.sos.logging.IDumpable;
	
	import flash.events.Event;
	
	public class Card extends DispatcherDataObject implements IDumpable
	{
		
		// -------------------------------------------------------------------------------
		// CONSTANTS
		// -------------------------------------------------------------------------------
		
		// JSON data property definition
		protected static const 			JSON_PROPERTY_CARD_ID:String			= "cardId";
		protected static const 			JSON_PROPERTY_INSTANCE_ID:String		= "instanceId";
		protected static const 			JSON_PROPERTY_CARD_NAME:String			= "cardName";
		protected static const 			JSON_PROPERTY_NAME:String				= "name";
		protected static const 			JSON_PROPERTY_CARD_TYPE:String			= "type";
		protected static const 			JSON_PROPERTY_CARD_SUBTYPE:String		= "subtype";
		protected static const 			JSON_PROPERTY_CARD_SET:String			= "";
		protected static const 			JSON_PROPERTY_DESCRIPTION:String		= "";
		protected static const 			JSON_PROPERTY_IMAGE:String				= "image";
		protected static const 			JSON_PROPERTY_LIMIT:String				= "deckLimit";
		protected static const 			JSON_PROPERTY_ROLE:String				= "role";
		protected static const 			JSON_PROPERTY_SCHOOL:String				= "schoolId";
		protected static const 			JSON_PROPERTY_DURATION:String			= "duration";
		protected static const 			JSON_PROPERTY_COST:String				= "cost";
		protected static const 			JSON_PROPERTY_ACTIONTEXT:String			= "actionText";
		protected static const 			JSON_PROPERTY_SKILL:String				= "skill";
		
		// Default values
		protected static const			DEFAULT_INSTANCE_ID:int 				= DataObject.INVALID_ID;
		protected static const			DEFAULT_CARD_ID:int 					= DataObject.INVALID_ID;
		protected static const			DEFAULT_NAME:String 					= "";
		protected static const			DEFAULT_DESCRIPTION:String 				= "";
		protected static const			DEFAULT_IMAGE:String 					= "";
		protected static const			DEFAULT_LIMIT:int 						= 1;
		protected static const			DEFAULT_TYPE:CardType 					= CardType.ACTION;
		protected static const			DEFAULT_CARD_SET:CardSet 				= CardSet.BASIC_SET;
		protected static const			DEFAULT_CARD_KIND:CardKind 				= CardKind.INSTANCE;
		protected static const			DEFAULT_SKILL:int 						= 1;
		
		// Events
		public static const				EVENT_SCHOOLS_CHANGED:String 			= "schoolsChanged";
		
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		protected var _cardId:uint;
		protected var _instanceId:uint;
		protected var _name:String;
		protected var _description:String;
		protected var _image:String;
		protected var _limit:uint;
		protected var _type:CardType;
		protected var _schools:Vector.<School>;
		protected var _cardSet:CardSet;
		protected var _kind:CardKind;
		protected var _subtype:CardSubtype;
		protected var _skill:uint;
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTOR
		// -------------------------------------------------------------------------------
		
		/**
		 * !!! DO NOT INSTANCE THIS CLASS !!! 
		 * Use CardFactory.create method instead!
		 */		
		public function Card(kind:CardKind = null)
		{
			// Init object
			_schools = new Vector.<School>();
			// Init
			_kind = (kind != null) ? kind : DEFAULT_CARD_KIND;
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------
		
		public function get kind():CardKind
		{
			return _kind;
		}
		
		public function get cardId():uint
		{
			return _cardId;
		}
		
		public function set cardId(value:uint):void
		{
			_cardId = value;
		}
		
		public function get instanceId():uint
		{
			return _instanceId;
		}
		
		public function set instanceId(value:uint):void
		{
			_instanceId = value;
		}
		
		public function get name():String
		{
			return _name;
		}
		
		public function set name(value:String):void
		{
			_name = value;
		}
		
		public function get description():String
		{
			return _description;
		}
		
		public function set description(value:String):void
		{
			_description = value;
		}
		
		public function get image():String
		{
			return _image;
		}
		
		public function set image(value:String):void
		{
			_image = value;
		}
		
		public function get type():CardType
		{
			return _type;
		}
		
		public function set type(value:CardType):void
		{
			_type = value;
		}
		
		public function get limit():uint
		{
			return _limit;
		}
		
		public function set limit(value:uint):void
		{
			_limit = value;
		}
		
		public function get cardSet():CardSet
		{
			return _cardSet;
		}
		
		public function set cardSet(value:CardSet):void
		{
			_cardSet = value;
		}
		
		public function get schoolName():String
		{
			var name:String = "";
			
			if (isSingleSchool)
			{
				name = singleSchool.name;
			}
			else
			{
				for (var i:int=0; i<_schools.length; i++)
				{
					if (name != "") name += "-";
					// name += getSchool(i).name;
					name += _schools[i].name;
				}
			}
			return name;
		}
		
		public function get singleSchool():School
		{
			return _schools[0];
		}
		
		public function get schools():Array
		{
			var schools:Array = new Array();
			for (var i:int = 0; i< _schools.length; i++)
			{
				schools.push(_schools[i]);
			}
			return schools;
		}

		public function get isGenericSchool():Boolean
		{
			return hasSchool(School.GENERIC);
		}
		
		public function get isSingleSchool():Boolean
		{
			return _schools.length == 1;
		}
		
		public function get isMultiSchool():Boolean
		{
			return	_schools.length > 1;
		}
		
		public function get subtype():CardSubtype 
		{
			return _subtype;
		}
		
		public function set subtype(value:CardSubtype):void 
		{
			_subtype = value;
		}
		
		public function get skill():uint 
		{
			return _skill;
		}
		
		public function set skill(value:uint):void 
		{
			_skill = value;
		}
		
		// -------------------------------------------------------------------------------
		// PRIVATE METHODS
		// -------------------------------------------------------------------------------
		
		// DATA OBJECT IMPLEMENTATION
		
		override protected function validate(data:Object):void
		{
			// Check by CardKind
			switch(_kind)
			{
				case CardKind.DEFINITION:
				{
					if (!data.hasOwnProperty(JSON_PROPERTY_CARD_ID)) 	throwLoadMissingPropError(JSON_PROPERTY_CARD_ID);
					if (!data.hasOwnProperty(JSON_PROPERTY_LIMIT)) 		throwLoadMissingPropError(JSON_PROPERTY_LIMIT);
					break;
				}
				case CardKind.INSTANCE:
				{
					if (!data.hasOwnProperty(JSON_PROPERTY_CARD_ID)) 	throwLoadMissingPropError(JSON_PROPERTY_CARD_ID);
					if (!data.hasOwnProperty(JSON_PROPERTY_LIMIT)) 		throwLoadMissingPropError(JSON_PROPERTY_LIMIT);
					break;
				}
				case CardKind.GAME_INSTANCE:
				{
					break;
				}
			}
			// Check for old parsing mode LT_TODO: remove, old parsing deprecated
			if (Application.instance.config.useOldActionCardParsing)
			{
				if (!data.hasOwnProperty(JSON_PROPERTY_INSTANCE_ID))	throwLoadMissingPropError("instance id");	
			}
			// Required data
			if (!data.hasOwnProperty(JSON_PROPERTY_CARD_TYPE)) 		throwLoadMissingPropError(JSON_PROPERTY_CARD_TYPE);
			if (!data.hasOwnProperty(JSON_PROPERTY_CARD_NAME) && 
				!data.hasOwnProperty(JSON_PROPERTY_NAME)) 			throwLoadMissingPropError("name");
			
			/* LT 2013-03-05 Old version without all kinds handling
			
			// CardKind.GAME_REFERENCE card type
			if (_kind != CardKind.GAME_REFERENCE) 
			{
				if (!data.hasOwnProperty(JSON_PROPERTY_CARD_ID)) 	throwLoadMissingPropError("card id");
				if (!data.hasOwnProperty(JSON_PROPERTY_LIMIT)) 		throwLoadMissingPropError("limit");
				// LT_TODO: check removed if (!data.hasOwnProperty(JSON_PROPERTY_CARD_SET)) 	throwDataMissingError("card set");
			}
			
			if (Application.instance.config.useOldActionCardParsing)
			{
				if (!data.hasOwnProperty(JSON_PROPERTY_INSTANCE_ID))	throwLoadMissingPropError("instance id");	
			}
			// Required data
			if (!data.hasOwnProperty(JSON_PROPERTY_CARD_TYPE)) 		throwLoadMissingPropError("type");
			if (!data.hasOwnProperty(JSON_PROPERTY_CARD_NAME) && 
				!data.hasOwnProperty(JSON_PROPERTY_NAME)) 			throwLoadMissingPropError("name");
			
			// LT_TODO: add needed fields when json is changed
			*/
		}
		
		override protected function fill(data:Object):void
		{
			if (data.hasOwnProperty(JSON_PROPERTY_CARD_ID)) 	_cardId 	= uint(data[JSON_PROPERTY_CARD_ID]);
			if (data.hasOwnProperty(JSON_PROPERTY_INSTANCE_ID)) _instanceId = uint(data[JSON_PROPERTY_INSTANCE_ID]);
			if (data.hasOwnProperty(JSON_PROPERTY_CARD_NAME)) 	_name 		= data[JSON_PROPERTY_CARD_NAME];
			if (data.hasOwnProperty(JSON_PROPERTY_NAME)) 		_name 		= data[JSON_PROPERTY_NAME];
			if (data.hasOwnProperty(JSON_PROPERTY_LIMIT)) 		_limit		= int(data[JSON_PROPERTY_LIMIT]);// Card.CARD_LIMIT;
			if (data.hasOwnProperty(JSON_PROPERTY_IMAGE)) 		_image		= data[JSON_PROPERTY_IMAGE];
			if (data.hasOwnProperty(JSON_PROPERTY_CARD_SUBTYPE)) _subtype	= CardSubtype.getById(uint(data[JSON_PROPERTY_CARD_SUBTYPE]));
			if (data.hasOwnProperty(JSON_PROPERTY_SKILL)) 		_skill		= uint(data[JSON_PROPERTY_SKILL]);
			// LT_TODO: change when card set is passed via json
			_cardSet	= CardSet.BASIC_SET; 
			// LT_TODO: add needed fields when json is changed
			
		}
		
		protected function getSchoolIndex(school:School):int
		{
			// return _schools.getItemAt(index) as School;
			for (var i:int = 0; i<_schools.length; i++)
			{
				if (_schools[i].id == school.id) return i;
			}
			return -1;
		}
		
		protected function addSchool(school:School):void
		{
			if (!hasSchool(school))
			{
				_schools.push(school);
				// Dispatch event EVENT_SCHOOLS_CHANGED
				dispatchSchoolsChanged();
			}
		}
		
		protected function removeSchool(school:School):void
		{
			var index:int = getSchoolIndex(school);
			if (index > -1)
			{
				_schools.splice(index, 1);
			}
			//			if (hasSchool(school))
			//			{
			//				_schools.removeItem(school);
			//				// Dispatch event EVENT_SCHOOLS_CHANGED
			//				dispatchSchoolsChanged();
			//			}
		}
		
		// EVENT DISPATCHERS
		
		protected function dispatchSchoolsChanged():void
		{
			dispatchEvent(new Event(EVENT_SCHOOLS_CHANGED));
		}
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
		
		public function hasSchool(school:School):Boolean
		{
			return  getSchoolIndex(school) > -1;
		}
		
		public function matchSchools(schools:Array):Boolean
		{
			for (var i:int = 0; i < schools.length; i++)
			{
				if (!hasSchool(schools[i] as School)) return false;
			}
			return true;
		}
		
		public function equals(card:Card):Boolean
		{
			return 	_cardId		== card.cardId && 
					_instanceId == card.instanceId;
		}
		
		public function copy(card:Card):void
		{
			if (_type != card.type) throw new Error("Card copy failed, type '" + card.type.name + "' does not match with current card type");
			// Copy
			_cardId			= card.cardId;
			_instanceId		= card.instanceId;
			_name			= card.name;
			_description	= card.description;
			_image			= card.image;
			_limit			= card.limit;
			_cardSet		= card.cardSet;
			_skill			= card.skill;
			// Copy schools
			_schools.splice(0, _schools.length);
			for (var i:int = 0; i < card.schools.length; i++) _schools.push(card.schools[i]);
		}
		
		public function clone():Card
		{
			var clone:Card = CardFactory.createEmptyCard(_type);
			clone.copy(this);
			return clone;
		}
		
		public function duplicate(kind:CardKind, instanceId:uint):Card
		{
			// Creates the clone
			var clone:Card = CardFactory.createEmptyCard(_type, kind == null ? _kind : kind);
			clone.copy(this);
			// Forces the instance id
			clone.instanceId = instanceId;
			return clone;
		}
		
		public function update():void
		{
			
		}
		
		override public function clear():void
		{
			_cardId 		= DEFAULT_CARD_ID;
			_instanceId		= DEFAULT_INSTANCE_ID;
			_name			= DEFAULT_NAME;
			_description	= DEFAULT_DESCRIPTION;
			_image			= DEFAULT_IMAGE;
			_limit			= DEFAULT_LIMIT;
			_cardSet		= DEFAULT_CARD_SET;
			_skill			= DEFAULT_SKILL;
		}
		
		public function dump(source:Array = null, indentDepth:int = 0):Array
		{
			return Dumper.dump(this, null, source, indentDepth);
		}
		
	}
}